package str

import (
	"fmt"
	"strings"
)

func Fun() {
	// 获取字符串长度
	LenOfUTF8()
	// 查找子串在字符串中出现的位置
	IndexOfChar()
	// 判断字符串中是否包含子串
	HaveSubStr()
	// 字符串比较
	Compare()
	// 字符串转换
	Convert()
	// 切割字符串
	Split()
	// 字符串格式截取
	Trim()

}

// LenOfUTF8 获取字符串长度
func LenOfUTF8() {
	str1 := "gaoxizhi"

	// 注意: Go语言编码方式是UTF-8，在UTF-8中一个汉字占3个字节
	fmt.Println(len(str1)) // 8

	// 注意byte占1个字节，只能保存字符不能保存汉字，因为一个汉字占用3个字节
	arr1 := []byte(str1)
	fmt.Println(len(arr1)) // 8

	str2 := "gaox.net 光而不耀"
	fmt.Println(len(str2)) // 21

	// 如果字符串中包含中文，又想精确计算字符串中字符的个数而不是占用的字节
	// 那么必须先将字符串转换为rune类型数组
	arr2 := []rune(str2)
	fmt.Println(len(arr2)) // 13
}

// IndexOfChar 查找子串在字符串中出现的位置
func IndexOfChar() {
	bright := "光而不耀 bright without being dazzling"

	// 查找`字符`在字符串中第一次出现的位置，找不到返回-1
	indexOfChar := strings.IndexByte(bright, 'g')
	fmt.Println(indexOfChar) // 16

	// 查找`汉字`OR`字符`在字符串中第一次出现的位置，找不到返回-1
	indexOfChar = strings.IndexRune(bright, '耀')
	fmt.Println(indexOfChar) // 9
	indexOfChar = strings.IndexRune(bright, 'g')
	fmt.Println(indexOfChar) // 16

	// 查找`汉字`OR`字符`中任意一个在字符串中第一次出现的位置，找不到返回-1
	indexOfChar = strings.IndexAny(bright, "gao")
	fmt.Println(indexOfChar) // 16

	// 会把 gaoxizhi 拆开逐个查找，g、a、o、光 只要任意一个被找到，立刻停止查找
	indexOfChar = strings.IndexAny(bright, "gao光")
	fmt.Println(indexOfChar) // 0

	// 查找`子串`在字符串第一次出现的位置，找不到返回-1
	indexOfChar = strings.Index(bright, "out")
	fmt.Println(indexOfChar) // 24

	// 会把 out 当做一个整体去查找，而不是拆开
	indexOfChar = strings.Index(bright, "gao")
	fmt.Println(indexOfChar) // -1

	// 可以查找字符也可以查找汉字
	indexOfChar = strings.Index(bright, "耀")
	fmt.Println(indexOfChar) // 9 按照 byte 顺序

	// 会将字符串先转换为 []rune，然后遍历 rune 切片逐个取出传给自定义函数
	// 只要函数返回true,代表符合我们的需求，既立即停止查找
	indexOfChar = strings.IndexFunc(bright, judgeHaveSpecialChar)
	fmt.Println(indexOfChar) // 15

	// 倒序查找`子串`在字符串第一次出现的位置，找不到返回-1
	indexOfChar = strings.LastIndex(bright, "g")
	fmt.Println(indexOfChar) // 41
}

// HaveSubStr 判断字符串中是否包含子串
func HaveSubStr() {
	bright := "光而不耀 bright without being dazzling"

	// 查找`子串`在字符串中是否存在，存在返回 true，不存在返回false
	// 底层实现就是调用strings.Index函数
	haveSubStr := strings.Contains(bright, "ing")
	fmt.Println(haveSubStr) // true

	// 查找`汉字`OR`字符`在字符串中是否存在, 存在返回true, 不存在返回false
	// 底层实现就是调用strings.IndexRune函数
	haveSubStr = strings.ContainsRune(bright, 'g')
	fmt.Println(haveSubStr) // true
	haveSubStr = strings.ContainsRune(bright, '耀')
	fmt.Println(haveSubStr) // true

	// 查找`汉字`OR`字符`中任意一个在字符串中是否存在, 存在返回true, 不存在返回false
	// 底层实现就是调用strings.IndexAny函数
	haveSubStr = strings.ContainsAny(bright, " bright")
	fmt.Println(haveSubStr) // true

	// 判断字符串是否已某个字符串开头
	haveSubStr = strings.HasPrefix("gaox.net", "gao")
	fmt.Println(haveSubStr) // true

	// 判断字符串是否已某个字符串结尾
	haveSubStr = strings.HasSuffix("gaox.site", ".site")
	fmt.Println(haveSubStr) // true
}

// Compare 字符串比较
func Compare() {
	// 比较两个字符串大小, 会逐个字符地进行比较ASCII值
	// 第一个参数 > 第二个参数 返回 1
	// 第一个参数 < 第二个参数 返回 -1
	// 第一个参数 == 第二个参数 返回 0
	res := strings.Compare("bcd", "abc")
	fmt.Println(res) // 1

	res = strings.Compare("bcd", "bdc")
	fmt.Println(res) // -1

	res = strings.Compare("bcd", "bcd")
	fmt.Println(res) // 0

	// 判断两个字符串是否相等，可以判断字符和中文
	// 判断时会忽略大小写进行判断
	res2 := strings.EqualFold("abc", "def")
	fmt.Println(res2) // false

	res2 = strings.EqualFold("abc", "abc")
	fmt.Println(res2) // true

	res2 = strings.EqualFold("abc", "ABC")
	fmt.Println(res2) // true

	res2 = strings.EqualFold("光而不耀", "光而不耀")
	fmt.Println(res2) // true
}

// Convert 字符串转换
func Convert() {
	// 将字符串转换为小写
	res := strings.ToLower("GaoXiZhi")
	fmt.Println(res) // gaoxizhi

	// 将字符串转换为大写
	res = strings.ToUpper("gaoxizhi")
	fmt.Println(res) // GAOXIZHI

	// 将字符串转换为标题格式，大部分`字符`标题格式就是大写
	res = strings.ToTitle("hello gaox")
	fmt.Println(res) // HELLO GAOX

	res = strings.ToTitle("HELLO GAOX")
	fmt.Println(res) // HELLO GAOX

	// 将单词首字母变为大写，其它字符不，单词之间用空格OR特殊字符隔开
	res = strings.Title("hello gaox")
	fmt.Println(res) // Hello Gaox
}

// Split 按照指定字符串切割原字符串用，切割字符串
func Split() {
	arr1 := strings.Split("a,b,c", ",")
	fmt.Println(arr1) // [a b c]

	arr2 := strings.Split("aoboc", "o")
	fmt.Println(arr2) // [a b c]

	// 按照指定字符串切割原字符串，并且指定切割为几份
	// 如果最后一个参数为0，那么会范围一个空数组
	arr3 := strings.SplitN("a,b,c", ",", 2)
	fmt.Println(arr3) // [a b,c]

	arr4 := strings.SplitN("a,b,c", ",", 0)
	fmt.Println(arr4) // []

	// 按照指定字符串切割原字符串，切割时包含指定字符串
	arr5 := strings.SplitAfter("a,b,c", ",")
	fmt.Println(arr5) // [a, b, c]

	// 按照指定字符串切割原字符串，切割时包含指定字符串，并且指定切割为几份
	arr6 := strings.SplitAfterN("a,b,c", ",", 2)
	fmt.Println(arr6) // [a, b,c]

	// 按照空格切割字符串，多个空格会合并为一个空格处理
	arr7 := strings.Fields("a b c d")
	fmt.Println(arr7) // [a b c d]

	// 将字符串转换成切片传递给函数之后由函数决定如何切割，类似于IndexFunc
	arr8 := strings.FieldsFunc("a,b,c", judgeHaveSpecialChar)
	fmt.Println(arr8) // [a b c]

	// 将字符串切片按照指定连接符号转换为字符串
	sce := []string{"aa", "bb", "cc"}
	str1 := strings.Join(sce, "-")
	fmt.Println(str1) // aa-bb-cc

	// 返回count个s串联的指定字符串
	str2 := strings.Repeat("abc", 2)
	fmt.Println(str2) // abcabc

	// 替换字符串
	str3 := "abcdefabcdefabc"
	// 第一个参数: 需要替换的字符串
	// 第二个参数: 旧字符串
	// 第三个参数: 新字符串
	// 第四个参数: 用新字符串 替换多少个旧字符串
	// 	注意点: 传入-1代表只要有旧字符串就替换
	// 	注意点: 替换之后会生成新字符串，原字符串不会受到影响
	str4 := strings.Replace(str3, "abc", "-", -1)
	fmt.Println(str3) // abcdefabcdefabc

	fmt.Println(str4) // -def-def-
}

// Trim 字符串格式截取
func Trim() {
	// 去除字符串两端指定字符
	str1 := strings.Trim("-abc-def-", "!")
	fmt.Println(str1) // abc-def

	// 去除字符串左端指定字符
	str2 := strings.TrimLeft("-abc-def-", "!")
	fmt.Println(str2) // abc-def-

	// 去除字符串右端指定字符
	str3 := strings.TrimRight("-abc-def-", "!")
	fmt.Println(str3) // -abc-def

	// 去除字符串两端空格
	str4 := strings.TrimSpace(" abc-def ")
	fmt.Println(str4) // abc-def

	// 按照方法定义规则,去除字符串两端符合规则内容
	str5 := strings.TrimFunc("-abc-def-", judgeHaveSpecialChar)
	fmt.Println(str5) // abc-def

	// 按照方法定义规则,去除字符串左端符合规则内容
	str6 := strings.TrimLeftFunc("-abc-def-", judgeHaveSpecialChar)
	fmt.Println(str6) // abc-def-

	// 按照方法定义规则,去除字符串右端符合规则内容
	str7 := strings.TrimRightFunc("-abc-def-", judgeHaveSpecialChar)
	fmt.Println(str7) // -abc-def

	// 取出字符串开头的指定字符串
	str8 := strings.TrimPrefix("gaox - golang.avi", "gaox - ")
	fmt.Println(str8) // golang.avi

	// 取出字符串结尾的指定字符串
	str9 := strings.TrimSuffix("gaox - golang.avi", ".avi")
	fmt.Println(str9) // gaox - golang
}

// judgeHaveSpecialChar 判定包含指定字符
func judgeHaveSpecialChar(r rune) bool {
	fmt.Printf("被调用了，当前传入的是%c\n", r)
	return r == 'i'
}
